import os
from collections import OrderedDict
from pathlib import Path

import pandas as pd

from ...exceptions import TdxFileNotFoundException
from ..base import BaseReader


class TdxMinBarReader(BaseReader):
    """
    读取通达信分钟数据
    """

    def parse_data_by_file(self, fname):
        """

        :param fname:
        :return:
        """
        if not os.path.isfile(fname):
            raise TdxFileNotFoundException('no tdx kline data, pleaes check path %s', fname)

        data = []

        with open(fname, 'rb') as f:
            raw_li = self.unpack_records('<HHIIIIfII', f.read())

            for row in raw_li:
                year, month, day = self._parse_date(row[0])
                hour, minute = self._parse_time(row[1])

                data.append(OrderedDict([
                    ('date', '%04d-%02d-%02d %02d:%02d' % (year, month, day, hour, minute)),
                    ('year', year),
                    ('month', month),
                    ('day', day),
                    ('hour', hour),
                    ('minute', minute),
                    ('open', row[2] / 100),
                    ('high', row[3] / 100),
                    ('low', row[4] / 100),
                    ('close', row[5] / 100),
                    ('amount', row[6]),
                    ('volume', row[7]),
                    # ('unknown', row[8])
                ]))

            return data

    def get_df(self, code_or_file, exchange=None):
        """

        :param code_or_file:
        :param exchange:
        :return:
        """
        # 只传入了一个参数
        data = self.parse_data_by_file(code_or_file)
        df = pd.DataFrame(data=data)
        df.index = pd.to_datetime(df.date)

        return df[['open', 'high', 'low', 'close', 'amount', 'volume']]

    @staticmethod
    def _parse_date(num):
        """

        :param num:
        :return:
        """
        year = num // 2048 + 2004
        month = (num % 2048) // 100
        day = (num % 2048) % 100

        return year, month, day

    @staticmethod
    def _parse_time(num):
        """

        :param num:
        :return:
        """
        return (num // 60), (num % 60)


class TdxLCMinBarReader(BaseReader):
    """
    读取通达信分钟数据
    """

    def parse_data_by_file(self, fname):
        """

        :param fname:
        :return:
        """
        if not Path(fname).is_file():
            raise TdxFileNotFoundException('no tdx kline data, pleaes check path %s', fname)

        data = []

        with open(fname, 'rb') as f:
            raw_li = self.unpack_records('<HHfffffII', f.read())

            for row in raw_li:
                year, month, day = self._parse_date(row[0])
                hour, minute = self._parse_time(row[1])

                data.append(OrderedDict([
                    ('date', '%04d-%02d-%02d %02d:%02d' % (year, month, day, hour, minute)),
                    ('year', year),
                    ('month', month),
                    ('day', day),
                    ('hour', hour),
                    ('minute', minute),
                    ('open', row[2]),
                    ('high', row[3]),
                    ('low', row[4]),
                    ('close', row[5]),
                    ('amount', row[6]),
                    ('volume', row[7]),
                    # ('unknown', row[8])
                ]))

            return data

    def get_df(self, code_or_file, exchange=None):
        """

        :param code_or_file:
        :param exchange:
        :return:
        """
        # 只传入了一个参数
        data = self.parse_data_by_file(code_or_file)

        df = pd.DataFrame(data=data)
        df.index = pd.to_datetime(df.date)

        return df[['open', 'high', 'low', 'close', 'amount', 'volume']]

    @staticmethod
    def _parse_date(num):
        """

        :param num:
        :return:
        """
        year = num // 2048 + 2004
        month = (num % 2048) // 100
        day = (num % 2048) % 100

        return year, month, day

    @staticmethod
    def _parse_time(num):
        """

        :param num:
        :return:
        """
        return (num // 60), (num % 60)
